package com.supreme.studyserver.controller;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSONObject;
import com.supreme.commonboot.utils.AjaxResp;
import com.supreme.studyserver.component.AuthConfig;
import com.supreme.studyserver.component.QumBeanFactory;
import com.supreme.studyserver.entity.Test;
import com.supreme.studyserver.service.BeanService;
import com.supreme.studyserver.service.KeyService;
import com.supreme.studyserver.service.MallService;
import com.supreme.studyserver.service.mall.SuperMallService;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.openjdk.jol.info.ClassLayout;
import org.reflections.Reflections;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;

@RestController
@RequestMapping(value = "bean")
public class BeanController {

    @Resource
    private ThreadPoolTaskExecutor supremeTaskExecutor;

//    @Autowired
//    @Qualifier(value = "tbmMallService")
//    private MallService mallService;

    @Resource
    private List<MallService> mallService;

    @Resource
    private SuperMallService superMallService;

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    @Resource
    private BeanFactory beanFactory;

    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private DataSource dataSource;

    @Resource
    private BeanService beanService;

    @Resource
    private JSONObject singletonScope;

    @Resource
    private JSONObject prototypeScope;

    @Resource
    private JSONObject requestScope;

    @Resource
    private JSONObject sessionScope;

    @GetMapping(value = "getBean/{beanName}")
    public AjaxResp getBean(@PathVariable(value = "beanName") String beanName) {
        Object bean = beanFactory.getBean(beanName);
        System.out.println("bean = " + bean);
        return AjaxResp.instance(bean.toString());
    }

    @GetMapping(value = "hasBean/{beanName}")
    public AjaxResp hasBean(@PathVariable(value = "beanName") String beanName) {
        final boolean result = QumBeanFactory.beanFactory.containsSingleton(beanName);
        return AjaxResp.instance(result);
    }

    @GetMapping(value = "getAuthConfigBean")
    public AjaxResp getAuthConfigBean() {
        final AuthConfig bean = QumBeanFactory.beanFactory.getBean(AuthConfig.class);
        System.out.println("bean = " + bean);
        return AjaxResp.instance();
    }

    @GetMapping(value = "getTaskExecutor/{beanName}")
    public AjaxResp getTaskExecutor(@PathVariable(value = "beanName") String beanName) {
        TaskExecutor bean = QumBeanFactory.beanFactory.getBean(beanName, TaskExecutor.class);
        System.out.println("bean = " + bean);
        return AjaxResp.instance();
    }

    @GetMapping(value = "getMallService")
    public AjaxResp getMallService() {
        mallService.forEach(MallService::showMallName);
        return AjaxResp.instance();
    }

    @GetMapping(value = "getMallService/{mallName}")
    public AjaxResp getMallServiceByName(@PathVariable(value = "mallName") String mallName) {
        MallService mallService = superMallService.getMallService(mallName);
        mallService.showMallName();
        return AjaxResp.instance();
    }

    @GetMapping(value = "sqlSessionConfig")
    public AjaxResp sqlSessionConfig() {
        Configuration configuration = sqlSessionFactory.getConfiguration();
        return AjaxResp.instance(configuration);
    }

    @GetMapping(value = "dataSource")
    public AjaxResp dataSource() {
        DruidDataSource druidDataSource = (DruidDataSource) dataSource;
        int initialSize = druidDataSource.getInitialSize();
        int maxActive = druidDataSource.getMaxActive();
        int minIdle = druidDataSource.getMinIdle();
        return AjaxResp.instance(new JSONObject() {{
            put("initialSize", initialSize);
            put("maxActive", maxActive);
            put("minIdle", minIdle);
        }});
    }

    @GetMapping(value = "objectSize")
    public AjaxResp objectSize() {
        Integer intValue = 1;
        System.out.println(ClassLayout.parseInstance(intValue).toPrintable());

        Long longValue = 1L;
        System.out.println(ClassLayout.parseInstance(longValue).toPrintable());

        Float floatValue = 1F;
        System.out.println(ClassLayout.parseInstance(floatValue).toPrintable());

        Double doubleValue = 1D;
        System.out.println(ClassLayout.parseInstance(doubleValue).toPrintable());

        String stringValue = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        System.out.println(ClassLayout.parseInstance(stringValue).toPrintable());

        Byte byteValue = 1;
        System.out.println(ClassLayout.parseInstance(byteValue).toPrintable());

        Test test = new Test().setFirstName("1111111111").setLastName("2222222222");
        System.out.println(ClassLayout.parseInstance(test).toPrintable());

        List<Test> testList = new ArrayList<>(20);
        for (int i = 0; i < 20; i++) {
            testList.add(new Test().setFirstName(String.valueOf(i)).setLastName(String.valueOf(i)));
        }
        System.out.println(ClassLayout.parseInstance(testList).toPrintable());

        return AjaxResp.instance();
    }

    @GetMapping(value = "testScope")
    public AjaxResp testScope(@RequestParam(value = "type") Integer type,
                              @RequestParam(value = "data", required = false) String data) {
        switch (type) {
            case 1:
                if (Objects.nonNull(data)) {
                    singletonScope.put("data", data);
                }
                System.out.println("singletonScope.toJSONString() = " + singletonScope.toJSONString());
                beanService.singletonScope();
                break;

            case 2:
                if (Objects.nonNull(data)) {
                    prototypeScope.put("data", data);
                }
                System.out.println("prototypeScope.toJSONString() = " + prototypeScope.toJSONString());
                beanService.prototypeScope();
                break;

            case 3:
                if (Objects.nonNull(data)) {
                    requestScope.put("data", data);
                }
                System.out.println("requestScope.toJSONString() = " + requestScope.toJSONString());
                beanService.requestScope();
                break;
        }

        return AjaxResp.instance();
    }

    @GetMapping(value = "classPath")
    public AjaxResp classPath() {
        ClassPathResource classPathResource = new ClassPathResource("my-config.yml");
        YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
        yamlPropertiesFactoryBean.setResources(classPathResource);
        Properties properties = yamlPropertiesFactoryBean.getObject();
        System.out.println(properties.get("my-config.name"));
        return AjaxResp.instance();
    }

    @GetMapping(value = "getImplStep1")
    public AjaxResp getImplStep1() {
        Map<String, MallService> mallServiceMap = applicationContext.getBeansOfType(MallService.class);
        mallServiceMap.forEach(new BiConsumer<String, MallService>() {
            @Override
            public void accept(String s, MallService mallService) {
                System.out.println("s = " + s);
                mallService.showMallName();
            }
        });

        Map<String, KeyService> keyServiceMap = applicationContext.getBeansOfType(KeyService.class);
        keyServiceMap.forEach(new BiConsumer<String, KeyService>() {
            @Override
            public void accept(String s, KeyService keyService) {
                System.out.println("s = " + s);
                keyService.showKeyName();
            }
        });

        return AjaxResp.instance();
    }

    @GetMapping(value = "getImplStep2")
    public AjaxResp getImplStep2() {
        Reflections reflections = new Reflections("com.supreme.studyserver.service.mall");
        Set<Class<? extends MallService>> mallServices = reflections.getSubTypesOf(MallService.class);
        mallServices.forEach(new Consumer<Class<? extends MallService>>() {
            @Override
            public void accept(Class<? extends MallService> clazz) {
                System.out.println("clazz.getSimpleName() = " + clazz.getSimpleName());
            }
        });
        return AjaxResp.instance();
    }

    @GetMapping(value = "getImplStep3")
    public AjaxResp getImplStep3() throws IOException {
        String packageName = "com.supreme.studyserver.service.mall";
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(packageName) + "/**/*.class";
        org.springframework.core.io.Resource[] resources = applicationContext.getResources(pattern);

        //MetadataReader 的工厂类
        MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
        for (org.springframework.core.io.Resource resource : resources) {
            //用于读取类信息
            MetadataReader reader = readerFactory.getMetadataReader(resource);
            //扫描到的class
            ClassMetadata classMetadata = reader.getClassMetadata();
            String[] interfaceNames = classMetadata.getInterfaceNames();
            boolean anyMatch = Arrays.stream(interfaceNames).anyMatch(s -> s.equals(MallService.class.getName()));
            if (anyMatch) {
                System.out.println("interfaceNames = " + Arrays.toString(interfaceNames));
                System.out.println("classname: " + classMetadata.getClassName());
            }
        }
        return AjaxResp.instance();
    }
}

